/*************************************************************************
 * @file: face.cpp
 * @date: 01/04/2012
 * TOPOL v1_0 - (c)copyright 2012 TEC/UFF
 *************************************************************************
 * This is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 ************************************************************************/

// includes
//----------
#include "face.h"
#include "solid.h"
#include "halfedge.h"
#include "loop.h"
#include "vertex.h"
#include "isurface.h"
#include <iostream>


///////////////////////////////////////////////////
///  Constructor and Destructor Implementation  ///
///////////////////////////////////////////////////

//-------------------------------------------------------------------------
Face::Face( Solid* _s )
: m_faceno( 0 )
, m_prevf( NULL )
, m_nextf( _s->getFace() )
, m_fsolid( NULL )
, m_flout( NULL )
, m_floops( NULL )
, m_surface( new ISurface() )
, m_isSelected( false )
{
  Face* faceOfSolid = _s->getFace();
  if( faceOfSolid )
  {
    faceOfSolid->m_prevf = this;
  }
  _s->setFace( this );
  m_fsolid = _s;
}
//-------------------------------------------------------------------------

//-------------------------------------------------------------------------
Face::~Face()
{
  if( this->m_prevf )
    this->m_prevf->m_nextf = this->m_nextf;
  if( this->m_nextf )
    this->m_nextf->m_prevf = this->m_prevf;
  if(this == m_fsolid->getFace())
    m_fsolid->setFace( this->m_nextf );
  if( m_surface != NULL )
  {
    delete m_surface;
    m_surface = NULL;
  }
}
//-------------------------------------------------------------------------


///////////////////////////////////////
///  PUBLIC Methods Implementation  ///
///////////////////////////////////////

//-------------------------------------------------------------------------
size_t 
Face::getFaceno()
{
	return m_faceno;
}
//-------------------------------------------------------------------------

//-------------------------------------------------------------------------
Face* 
Face::getPrevFace()
{
  return m_prevf;
}
//-------------------------------------------------------------------------

//-------------------------------------------------------------------------
Face* 
Face::getNextf()
{
	return m_nextf;
}
//-------------------------------------------------------------------------

//-------------------------------------------------------------------------
Solid* 
Face::getSolid()
{
	return m_fsolid;
}
//-------------------------------------------------------------------------

//-------------------------------------------------------------------------
Loop* 
Face::getLoopOut()
{
  return m_flout;
}
//-------------------------------------------------------------------------

//-------------------------------------------------------------------------
Loop* 
Face::getFloops()
{
	return m_floops;
}
//-------------------------------------------------------------------------

//-------------------------------------------------------------------------
ISurface* 
Face::getSurface()
{
  return m_surface;
}
//-------------------------------------------------------------------------

//-------------------------------------------------------------------------
bool 
Face::isSelected()
{
  return m_isSelected;
}
//-------------------------------------------------------------------------

//-------------------------------------------------------------------------
void 
Face::setFaceno( size_t _f ) 
{
  m_faceno = _f;
}
//-------------------------------------------------------------------------

//-------------------------------------------------------------------------
void 
Face::setFlout( Loop* _loop ) 
{
  m_flout = _loop;
}
//-------------------------------------------------------------------------

//-------------------------------------------------------------------------
void 
Face::setLoop( Loop* _loop )
{
	m_floops = _loop;
}
//-------------------------------------------------------------------------

//-------------------------------------------------------------------------
void 
Face::setSelection( bool _select )
{
  m_isSelected = _select;
}
//-------------------------------------------------------------------------

//-------------------------------------------------------------------------
void 
Face::setSurface()
{
  // in case it is not the external face and it consists of a closed loop
  if( m_flout && m_flout->getArea() > 0.0 ) 
  {
    vector<IPoint> pol;
    HalfEdge* h = m_flout->getLedg();
    // before setup the polygon vertex list, ensures that
    // it should starts from a half-edge != any other half-edge mate
    do
    {
      if( m_flout->getLedg() == h->mate() )
      {
        m_flout->setLedg( m_flout->getLedg()->getNxt() );
        h = m_flout->getLedg();
      }
    }
    while((h = h->getNxt()) != m_flout->getLedg());
    // sets the polygon vertex list
    do
    {
      pol.push_back( *h->getVtx()->getPoint() );
      // removes the lamina edges
      if( h == h->getNxt()->mate() )
      {
        HalfEdge* h_next = h->getNxt()->getNxt();
        HalfEdge* h_prev = h->getPrv();
        while( h_prev == h_next->mate() )
        {
          pol.pop_back();
          h_next = h_next->getNxt();
          h_prev = h_prev->getPrv();
        }
        h = h_next;
        if( h_next->getVtx()->getVertexno() == m_flout->getLedg()->getVtx()->getVertexno() )
        {
          h = h_next->getPrv();
        }
      }
    }
    while((h = h->getNxt()) != m_flout->getLedg());
    // generates or regenerates the triangulation
    m_surface->generateSurfMesh( pol );
  }
}
//-------------------------------------------------------------------------
